﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Cosmos.Hardware;
using Cosmos.Core;

namespace Mirus.Kernel.Hardware.Drivers.TextScreen
{
    // Dont hold state here. This is a raw to hardware class. Virtual screens should be done
    // by memory moves
    public class TextScreen : Device
    {
        protected byte Color = 0x0F; // White
        // Empty + White
        protected UInt16 mClearCellValue = 0x000F;
        protected UInt32 mClearCellValue32;
        protected UInt32 mRow2Addr;
        protected UInt32 mScrollSize;
        protected UInt32 mRowSize32;

        protected Cosmos.Core.IOGroup.TextScreen IO = Cosmos.Core.Global.BaseIOGroups.TextScreen;
        protected readonly MemoryBlock08 mRAM;

        public TextScreen()
        {
            mRAM = IO.Memory.Bytes;
            mClearCellValue32 = (UInt32)(mClearCellValue << 16 | mClearCellValue);
            mRow2Addr = (UInt32)(Cols * 2);
            mScrollSize = (UInt32)(Cols * (Rows - 1) * 2);
            mRowSize32 = (UInt32)Cols * 2 / 4;
        }

        public UInt16 Rows { get { return 25; } }
        public UInt16 Cols { get { return 80; } }

        public void Clear()
        {
            IO.Memory.Fill(mClearCellValue32);
        }

        public void ScrollUp()
        {
            IO.Memory.MoveDown(0, mRow2Addr, mScrollSize);
            IO.Memory.Fill(mScrollSize, mRowSize32, mClearCellValue32);
        }

        public char this[int aX, int aY]
        {
            get
            {
                var xScreenOffset = (UInt32)((aX + aY * Cols) * 2);
                return (char)mRAM[xScreenOffset];
            }
            set
            {
                var xScreenOffset = (UInt32)((aX + aY * Cols) * 2);
                mRAM[xScreenOffset] = (byte)value;
                mRAM[xScreenOffset + 1] = Color;
            }
        }

        public void SetColors(ConsoleColor aForeground, ConsoleColor aBackground)
        {
            Color = (byte)((byte)(aForeground) | ((byte)(aBackground) << 4));
        }

        public void SetCursorPos(int aX, int aY)
        {
            char xPos = (char)((aY * Cols) + aX);
            // Cursor low byte to VGA index register
            IO.Idx3.Byte = 0x0F;
            IO.Data3.Byte = (byte)(xPos & 0xFF);
            // Cursor high byte to VGA index register
            IO.Idx3.Byte = 0x0E;
            IO.Data3.Byte = (byte)(xPos >> 8);
        }

    }
}
